package logger

import (
	"context"
	"log/slog"
	"os"
	"path/filepath"

	"gopkg.in/natefinch/lumberjack.v2"

	"torler.com/qingyue/pkg/env"
)

// initDefaultLogger initializes the default logger
func initDefaultLogger(cfg moduleConfig) {
	log := slog.Default()
	configure("default", cfg, log)

}

// initModuleLogger initializes a module logger
func initModuleLogger(moduleName string, cfg moduleConfig) {
	mu.Lock()
	defer mu.Unlock()

	if _, exists := moduleHandlers[moduleName]; !exists {
		logger := slog.New(slog.NewTextHandler(os.Stderr, nil)) // Temporary handler
		configure(moduleName, cfg, logger)
		moduleHandlers[moduleName] = logger
	}
}

func configure(moduleName string, cfg moduleConfig, logger *slog.Logger) {
	var level slog.Level
	switch cfg.Level {
	case "debug":
		level = slog.LevelDebug
	case "info":
		level = slog.LevelInfo
	case "warn":
		level = slog.LevelWarn
	case "error":
		level = slog.LevelError
	default:
		level = slog.LevelInfo
	}

	logFilePath := filepath.Join(env.GetLogDir(), cfg.Name)
	fileOutput := &lumberjack.Logger{
		Filename:   logFilePath,
		MaxSize:    cfg.MaxSize,
		MaxBackups: cfg.MaxBackups,
		MaxAge:     cfg.MaxAge,
		Compress:   cfg.Compress,
	}

	var handler slog.Handler

	if env.IsDev() || env.IsRunInDocker() {
		// Development: console (text) + file (JSON)
		consoleHandler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
			Level: level,
		})

		fileHandler := slog.NewJSONHandler(fileOutput, &slog.HandlerOptions{
			Level: level,
		})

		handler = newMultiHandler(consoleHandler, fileHandler)
	} else {
		// Production: file only (JSON)
		handler = slog.NewJSONHandler(fileOutput, &slog.HandlerOptions{
			Level: level,
		})
	}

	// Replace the logger's handler
	*logger = *slog.New(handler)
	logger.Info("模块日志初始化成功", "module", moduleName, "filename", cfg.Name)
}

// Default gets the default logger
func Default() *slog.Logger {
	return slog.Default()
}

// multiHandler implements simultaneous output to console and file
type multiHandler struct {
	handlers []slog.Handler
}

func newMultiHandler(handlers ...slog.Handler) *multiHandler {
	return &multiHandler{handlers: handlers}
}

func (h *multiHandler) Enabled(ctx context.Context, level slog.Level) bool {
	for _, handler := range h.handlers {
		if handler.Enabled(ctx, level) {
			return true
		}
	}
	return false
}

func (h *multiHandler) Handle(ctx context.Context, r slog.Record) error {
	var err error
	for _, handler := range h.handlers {
		if handler.Enabled(ctx, r.Level) {
			if e := handler.Handle(ctx, r.Clone()); e != nil {
				err = e
			}
		}
	}
	return err
}

func (h *multiHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
	handlers := make([]slog.Handler, len(h.handlers))
	for i, handler := range h.handlers {
		handlers[i] = handler.WithAttrs(attrs)
	}
	return newMultiHandler(handlers...)
}

func (h *multiHandler) WithGroup(name string) slog.Handler {
	handlers := make([]slog.Handler, len(h.handlers))
	for i, handler := range h.handlers {
		handlers[i] = handler.WithGroup(name)
	}
	return newMultiHandler(handlers...)
}
